﻿//-----------------------------------------------------------------------------
// File: ControlRepeater.cs
//
// Copyright (c) Dmitry Shuklin. All rights reserved.
//-----------------------------------------------------------------------------
using System.ComponentModel;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;

namespace Cerebrum.Direct3D.Forms
{
    public class ControlRepeaterEventArgs : System.EventArgs
    {
        public Cerebrum.Direct3D.Forms.IShdRepeatedControl RepeatedControl;
    }

    public delegate void CreateRepeatedEventHandler(object sender, ControlRepeaterEventArgs re);

    public class ControlRepeater : Cerebrum.Direct3D.Forms.Control // System.Windows.Forms.ContainerControl
    {

        public event CreateRepeatedEventHandler CreateRepeatedControl;

        private System.Collections.ArrayList mArrayControls;
        private int mCountControls;
        private int mCountVisible;
        private int mFirstVisible;
        private float mControlHeight;
        private bool mUnderConstruct = true;
        private bool mScrolling = false;
        private int mTimerTicks = 0;

        public ControlRepeater()
        {
            mUnderConstruct = true;
            this.mScrollTimer = new System.Windows.Forms.Timer();
            this.mVScrollBar = new Cerebrum.Direct3D.Forms.Scrolling.VScrollBar();
            mVScrollBar.Size = new System.Drawing.SizeF(16, this.Size.Height);
            mVScrollBar.Dock = System.Windows.Forms.DockStyle.Right;
            mVScrollBar.Minimum = 0;
            mVScrollBar.Value = 0;
            mScrollTimer.Interval = 120;
            this.Controls.Add(mVScrollBar);
            mVScrollBar.Visible = false;
            mArrayControls = new System.Collections.ArrayList();

            mVScrollBar.ValueChanged += new System.EventHandler(mVScrollBar_ValueChanged);
            mScrollTimer.Tick += new System.EventHandler(mScrollTimer_Tick);
            this.Resize += new System.EventHandler(mControlRepeater_Resize);

            mUnderConstruct = false;
        }

        // UserControl1 overrides dispose to clean up the component list.


        private System.Windows.Forms.Timer mScrollTimer;
        private Cerebrum.Direct3D.Forms.Scrolling.VScrollBar mVScrollBar;
        //private System.Windows.Forms.VScrollBar mVScrollBar;

        public int ControlsCount
        {
            get
            {
                return mCountControls;
            }
            set
            {
                mCountControls = value;
                if (!mUnderConstruct)
                {
                    RefreshControls();
                }
            }
        }

        public void RefreshControls()
        {
            mControlHeight = 0;
            int i;
            for (i = 0; i <= mArrayControls.Count - 1; i++)
            {
                this.Controls.Remove((mArrayControls[i] as Control));
            }

            mArrayControls.Clear();
            RefreshArray();
            RefreshGrid();
        }

        private void RefreshArray()
        {
            if (!mUnderConstruct)
                if (mCountControls > 0)
                {
                    mUnderConstruct = true;
                    int i;
                    Cerebrum.Direct3D.Forms.IShdRepeatedControl rc = null;
                    Control uc = null;
                    if (mControlHeight == 0)
                    {
                        if (CreateRepeatedControl != null)
                        {
                            Cerebrum.Direct3D.Forms.ControlRepeaterEventArgs re = new Cerebrum.Direct3D.Forms.ControlRepeaterEventArgs();
                            re.RepeatedControl = null;
                            CreateRepeatedControl(this, re);
                            rc = re.RepeatedControl;
                        }
                        if (rc != null)
                        {
                            mControlHeight = (rc as Control).Size.Height;
                        }
                    }

                    if (mControlHeight > 0)
                    {
                        //mCountVisible = this.ClientSize.Height / mControlHeight + 2;
                        mCountVisible = (int)(this.Size.Height / mControlHeight + 2);
                        if (mCountVisible >= mCountControls)
                        {
                            mCountVisible = mCountControls;
                        }
                        // ''''''''''''''''''''''''''''''''''''

                        //  Refresh Layout:

                        System.Drawing.SizeF vSize;
                        //if (mCountControls * mControlHeight > this.ClientSize.Height)
                        if (mCountControls * mControlHeight > this.Size.Height)
                        {
                            //mVScrollBar.Maximum = (mCountControls + 1) * mControlHeight - this.ClientSize.Height + 1;
                            mVScrollBar.Maximum = (mCountControls + 1) * mControlHeight - this.Size.Height + 1;
                            // (mCountControls - mCountVisible + 3) * mControlHeight - mControlHeight \ 10

                            if (mVScrollBar.Maximum < mControlHeight)
                            {
                                mVScrollBar.SmallChange = 1;
                                mVScrollBar.LargeChange = mVScrollBar.Maximum;
                            }

                            else
                            {
                                mVScrollBar.SmallChange = mControlHeight / 10;
                                mVScrollBar.LargeChange = mControlHeight;
                            }

                            if (mVScrollBar.Value > mVScrollBar.Maximum - mVScrollBar.LargeChange)
                            {
                                mVScrollBar.Value = mVScrollBar.Maximum - mVScrollBar.LargeChange;
                            }

                            mVScrollBar.Enabled = true;
                            mVScrollBar.Visible = true;
                            vSize = new System.Drawing.SizeF(this.Size.Width - mVScrollBar.Size.Width - 1, mControlHeight);
                        }

                        else
                        {
                            mVScrollBar.Visible = false;
                            mVScrollBar.Enabled = false;
                            mVScrollBar.Value = 0;
                            vSize = new System.Drawing.SizeF(this.Size.Width - 1, mControlHeight);
                        }


                        for (i = mCountVisible; i <= mArrayControls.Count - 1; i++)
                        {
                            this.Controls.Remove((mArrayControls[i] as Control));
                        }

                        if (mArrayControls.Count > mCountVisible)
                        {
                            while (mArrayControls.Count > mCountVisible)
                            {
                                mArrayControls.RemoveAt(mArrayControls.Count - 1);
                            }
                        }
                        if (mArrayControls.Count < mCountVisible)
                        {
                            while (mArrayControls.Count < mCountVisible)
                            {
                                mArrayControls.Add(null);
                            }
                        }

                        for (i = 0; i <= mCountVisible - 1; i++)
                        {
                            if (mArrayControls[i] == null)
                            {
                                if (rc == null)
                                {
                                    if (CreateRepeatedControl != null)
                                    {
                                        Cerebrum.Direct3D.Forms.ControlRepeaterEventArgs re = new Cerebrum.Direct3D.Forms.ControlRepeaterEventArgs();
                                        re.RepeatedControl = null;
                                        CreateRepeatedControl(this, re);
                                        rc = re.RepeatedControl;
                                    }
                                }

                                rc.Index = -1;
                                uc = (rc as Control);
                                mArrayControls[i] = uc;
                                uc.Visible = false;
                                //uc.TabStop = false;
                                this.Controls.Add(uc);
                                uc = null;
                                rc = null;
                            }

                            (mArrayControls[i] as Cerebrum.Direct3D.Forms.Control).Size = vSize;
                            //(mArrayControls[i] as System.Windows.Forms.Control).Size = vSize;
                        }
                    }

                    mUnderConstruct = false;
                }
                else
                {
                    mVScrollBar.Visible = false;
                    mVScrollBar.Enabled = false;
                    mVScrollBar.Value = 0;
                }

        }

        private void RefreshGrid()
        {
            if (mCountControls > 0 && !mUnderConstruct && mControlHeight > 0)
            {
                mUnderConstruct = true;
                mFirstVisible = (int)(mVScrollBar.Value / mControlHeight);
                if (mFirstVisible >= mCountControls)
                {
                    mFirstVisible = mCountControls - 1;
                }

                int i;
                int jy;
                int dy;
                ArrayList qs = new ArrayList();
                ArrayList ws = new ArrayList();
                Control uc;
                jy = mFirstVisible;
                dy = (int)(mVScrollBar.Value % mControlHeight);
                for (i = 0; i <= mCountVisible - 1; i++)
                {
                    if (jy < mCountControls)
                    {
                        qs.Add(jy);
                        jy = jy + 1;
                    }

                    if (mArrayControls[i] != null)
                    {
                        ws.Add(mArrayControls[i]);
                    }

                }

                for (i = 0; i < mCountVisible; i++)
                {
                    uc = (mArrayControls[i] as Control);
                    if (uc != null)
                    {
                        Cerebrum.Direct3D.Forms.IShdRepeatedControl rc = (uc as Cerebrum.Direct3D.Forms.IShdRepeatedControl);
                        jy = rc.Index;
                        rc.Scrolling = mScrolling;
                        if (qs.Contains(jy))
                        {
                            qs.Remove(jy);
                            ws.Remove(uc);
                            uc.Location = new System.Drawing.PointF(0, (jy - mFirstVisible) * mControlHeight - dy);
                            uc.Visible = true;
                            // '.Refresh()

                        }

                    }

                    uc = null;
                }

                for (i = qs.Count - 1; i >= 0; i--)
                {
                    jy = (int)(qs[i]);
                    qs.Remove(jy);
                    Control wts = (ws[0] as Control);
                    wts.Location = new System.Drawing.PointF(0, (jy - mFirstVisible) * mControlHeight - (mVScrollBar.Value % mControlHeight));
                    wts.Visible = true;
                    // '.Refresh()

                    (ws[0] as Cerebrum.Direct3D.Forms.IShdRepeatedControl).Index = jy;
                    ws.Remove(ws[0]);
                }

                for (i = ws.Count - 1; i >= 0; i--)
                {
                    (ws[i] as Control).Visible = false;
                    (ws[i] as Cerebrum.Direct3D.Forms.IShdRepeatedControl).Index = -1;
                }

                mUnderConstruct = false;
            }
        }

        private void RefreshScrolling()
        {
            int i;
            for (i = 0; i <= mCountVisible - 1; i++)
            {
                if (mArrayControls[i] != null)
                {
                    (mArrayControls[i] as Cerebrum.Direct3D.Forms.IShdRepeatedControl).Scrolling = mScrolling;
                }

            }

        }

        public void mControlRepeater_Resize(object sender, System.EventArgs e)
        {
            mScrolling = false;
            RefreshArray();
            RefreshGrid();
        }

        public void mVScrollBar_ValueChanged(object sender, System.EventArgs e)
        {
            mScrolling = true;
            RefreshGrid();
            if (!mScrollTimer.Enabled)
            {
                mScrollTimer.Enabled = true;
                mTimerTicks = 0;
            }

        }

        public void mScrollTimer_Tick(object sender, System.EventArgs e)
        {
            mTimerTicks += 1;
            if (mTimerTicks > 4)
            {
                mTimerTicks = 0;
                mScrollTimer.Enabled = false;
                if (mScrolling)
                {
                    mScrolling = false;
                    RefreshScrolling();
                }

            }

        }

    }

    public interface IShdRepeatedControl
    {
        int Index { get;set;}
        bool Scrolling { get;set;}
    }
}
